/*******************************************
 * Copyright 2007 Aphrodite Framework for javaME .
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the GNU Public License v2.0
 * which accompanies this distribution, and is available at
 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
 * Email : owner@aphroditeme.dev.java.net
 * Contributors:
 *     Kent Elton - initial API and implementation
 *******************************************/

package com.aphrodite.ui.widgets;

import java.util.Timer;
import java.util.TimerTask;
import java.util.Vector;

import javax.microedition.lcdui.Graphics;
import javax.microedition.lcdui.Image;

import com.aphrodite.util.geom.GeomUtil;

//must implement traverse
/**
 *A menu with horizontal sliding icons
 *<p>
 * Only one menu is visible at any time<br/> <img
 * src="../../../resources/slidingMenu1.png">
 *</p>
 * 
 * 
 * @author kentelt
 * 
 */
public final class SlidingIconsMenu extends TraversableWidget {
	private final class Ani extends TimerTask {
		public void run() {
			while (canSlide) {
				reDrawWidget();
				try {
					Thread.sleep(slideTime);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}
	}

	private boolean canSlide;
	private int dragPointX;
	private final Vector icons;
	private final Vector labels;

	private int pressPointX;

	// previous item index (during menu translation)
	int prevIndex = 0;

	// selected item index
	private int selectedIndex = 0;
	private volatile int slideTime = 100;

	private long startTranslationTime = 0;
	private Timer timer;

	// menu sliding translation properties
	private int translationDuration = 500;

	/**
	 * 
	 * @param x
	 * @param y
	 * @param width
	 *            of the widget
	 * @param height
	 *            of the widget
	 * 
	 */
	public SlidingIconsMenu(Theme theme, int width, int height) {
		super(theme, width, height);
		this.icons = new Vector();
		this.labels = new Vector();
	}

	public void addMenu(String label, Image icon) {
		if (icons.isEmpty()) {
			startSliding();
		}
		icons.addElement(icon);
		labels.addElement(label);

	}

	public void cleanUp() {
		icons.removeAllElements();
		labels.removeAllElements();
		canSlide = false;
		timer = null;
	}

	/**
	 * Get the current selected index
	 * 
	 * @return
	 */
	public int getSelectedIndex() {
		return selectedIndex;
	}

	private boolean isTranslating() {
		return prevIndex != selectedIndex;
	}

	public boolean moveLeft() {
		slideItem(-1);
		return true;
	}

	public boolean moveRight() {
		slideItem(1);
		return true;
	}

	public boolean pointerDrag(int px, int py) {
		if (isVisible && GeomUtil.withinBounds(px, py, x, y, width, height)) {
			dragPointX = px;
			return true;
		}
		return false;
	}

	public boolean pointerPress(int px, int py) {
		if (isVisible && GeomUtil.withinBounds(px, py, x, y, width, height)) {
			pressPointX = px;
			dragPointX = px;
			return true;
		}
		return false;
	}

	public boolean pointerRelease(int px, int py) {
		if (isVisible && GeomUtil.withinBounds(px, py, x, y, width, height)) {
			if (dragPointX < pressPointX) {
				slideItem(1);
			} else if (dragPointX > pressPointX) {
				slideItem(-1);
			} else if (dragPointX == pressPointX) {
				super.fire();
			}
			return true;
		}
		return false;
	}

	public void render(Graphics g) {
		if (!isVisible)
			return;
		capture(g, width, height, true);
		g.setColor(theme.fgColor);
		g.setFont(theme.widgetFont);
		// Draw when there are icons to be drawn
		if (!icons.isEmpty()) {
			g.drawString((String) labels.elementAt(selectedIndex), width / 2, height - 2, Graphics.BOTTOM
					| Graphics.HCENTER);
			if (selectedIndex != prevIndex) {
				int diff = (int) (System.currentTimeMillis() - startTranslationTime);
				if (diff > translationDuration) {
					diff = translationDuration;
				}
				int coeff = selectedIndex > prevIndex ? 1 : -1;
				int currentX = width / 2 - coeff * diff * width / translationDuration;
				int nextX = currentX + width * coeff;

				g.drawImage((Image) icons.elementAt(prevIndex), currentX, height / 2, Graphics.VCENTER
						| Graphics.HCENTER);
				g.drawImage((Image) icons.elementAt(selectedIndex), nextX, height / 2, Graphics.VCENTER
						| Graphics.HCENTER);
				if (diff >= translationDuration) {
					prevIndex = selectedIndex;
				}
			} else {
				g.drawImage((Image) icons.elementAt(selectedIndex), width / 2, height / 2, Graphics.VCENTER
						| Graphics.HCENTER);
			}
		}
		release(g, width, height, true);

	}

	/**
	 * Set the delay in the slide effect
	 * 
	 * @param millisec
	 *            Default is 100 ms
	 * @throws IllegalArgumentException
	 *             if <code>millisec</code> is <0
	 */
	public void setSlideInterval(int millisec) {
		if (millisec < 0) {
			throw new IllegalArgumentException();
		}
		slideTime = millisec;
	}

	public void setVisible(boolean isVisible) {
		super.setVisible(isVisible);
		/* stop bg thread when not visible */
		if (!isVisible) {
			startSliding();
		} else {
			stopSliding();
		}
	}

	private void slideItem(int delta) {
		prevIndex = selectedIndex;
		if (!isTranslating() && selectedIndex + delta >= 0 && selectedIndex + delta < labels.size()) {
			selectedIndex += delta;
		} else if (delta == -1) {
			selectedIndex = labels.size() - 1;
		} else {
			selectedIndex = 0;
		}
		startTranslationTime = System.currentTimeMillis();
	}

	private void startSliding() {
		if (!canSlide) {
			timer = new Timer();
			canSlide = true;
			timer.schedule(new Ani(), 0);
		}

	}

	private void stopSliding() {
		if (canSlide) {
			canSlide = false;
			timer.cancel();
			timer = null;
		}
	}

	protected boolean traverse(int dir, int viewportWidth, int viewportHeight, int[] visRect_inout) {
		return false;
	}

	protected void updateModel() {}

}
